package com.ezandroid.library.image;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory.Options;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.ImageSwitcher;
import android.widget.ImageView;

import com.ezandroid.library.image.ext.core.display.BlurBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.BlurFadeInBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.CircleBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.CircleBlurBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.CircleFadeInBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.CircleRingBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.FadeInBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.FadeOutBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.RoundedBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.RoundedBlurBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.RoundedFadeInBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.RoundedVignetteBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.RoundedVignetteBlurBitmapDisplayer;
import com.ezandroid.library.image.ext.core.display.RoundedVignetteFadeInBitmapDisplayer;
import com.ezandroid.library.image.ext.core.download.BaseImageDownloader;
import com.ezandroid.library.image.ext.core.imageaware.ImageSwitcherAware;
import com.ezandroid.library.image.ext.core.imageaware.SimpleViewAware;
import com.nostra13.universalimageloader.cache.disc.DiskCache;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache;
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.MemoryCache;
import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.ImageSize;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.assist.ViewScaleType;
import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
import com.nostra13.universalimageloader.core.download.ImageDownloader.Scheme;
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
import com.nostra13.universalimageloader.core.imageaware.ImageViewAware;
import com.nostra13.universalimageloader.core.imageaware.NonViewAware;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;
import com.nostra13.universalimageloader.utils.ImageSizeUtils;
import com.nostra13.universalimageloader.utils.L;
import com.nostra13.universalimageloader.utils.MemoryCacheUtils;
import com.nostra13.universalimageloader.utils.StorageUtils;

import java.io.File;
import java.io.IOException;

public class EZImageLoader {

    /**
     * 显示原始图片（默认）
     */
    public static final int DISPLAY_SIMPLE = 1 << 0;
    /**
     * 渐入显示图片
     */
    public static final int DISPLAY_FADE_IN = 1 << 1;
    /**
     * 显示圆角图片
     */
    public static final int DISPLAY_ROUND = 1 << 2;
    /**
     * 显示圆角晕影图片
     */
    public static final int DISPLAY_ROUND_VIGNETTE = 1 << 3;
    /**
     * 显示圆形图片
     */
    public static final int DISPLAY_CIRCLE = 1 << 4;
    /**
     * 显示圆形图片带圆环
     */
    public static final int DISPLAY_CIRCLE_RING = 1 << 5;
    /**
     * 显示高斯模糊图片
     */
    public static final int DISPLAY_BLUR = 1 << 6;
    /**
     * 渐出显示图片
     */
    public static final int DISPLAY_FADE_OUT = 1 << 7;

    private static Context mContext;
    private static ImageLoader mImageLoader;

    /**
     * 初始化图片加载器
     *
     * @param context
     */
    public static synchronized void init(Context context, String cacheDir) {
        init(context, cacheDir, 128 * 1024 * 1024);
    }

    /**
     * 初始化图片加载器
     *
     * @param context
     * @param cacheDir
     * @param diskCacheSize
     */
    public static synchronized void init(Context context, String cacheDir, long diskCacheSize) {
        mContext = context;
        mImageLoader = ImageLoader.getInstance();
        if (!mImageLoader.isInited()) {
            Options options = new Options();
            options.inPreferredConfig = Config.RGB_565;
            options.inSampleSize = 1;
            // 默认配置
            ImageLoaderConfiguration imageLoaderConfiguration = new ImageLoaderConfiguration.Builder(
                    mContext)
                    .threadPriority(Thread.NORM_PRIORITY - 1)
                    .threadPoolSize(Runtime.getRuntime().availableProcessors() + 1)
                    .tasksProcessingOrder(QueueProcessingType.FIFO)
                    .diskCache(
                            createDiskCache(context, cacheDir, new Md5FileNameGenerator(),
                                    diskCacheSize))
                    .memoryCache(createMemoryCache(25))
                    .imageDownloader(new BaseImageDownloader(context))
                    .defaultDisplayImageOptions(
                            new DisplayImageOptions.Builder().cacheInMemory(true).cacheOnDisk(true)
                                    .imageScaleType(ImageScaleType.EXACTLY)
                                    .considerExifParams(false).decodingOptions(options).build())
                    .build();

            mImageLoader.init(imageLoaderConfiguration);
        }
    }

    public static synchronized void init(Context context, ImageLoaderConfiguration config) {
        mContext = context;
        mImageLoader = ImageLoader.getInstance();
        if (!mImageLoader.isInited()) {
            mImageLoader.init(config);
        }
    }

    private static MemoryCache createMemoryCache(int availableMemoryPercent) {
        long availableMemory = Runtime.getRuntime().maxMemory();
        return new LruMemoryCache((int) (availableMemory * (availableMemoryPercent / 100f)));
    }

    private static DiskCache createDiskCache(Context context, String cacheDir,
                                             FileNameGenerator diskCacheFileNameGenerator, long diskCacheSize) {
        // 备用的缓存目录
        File reserveCacheDir = StorageUtils.getIndividualCacheDirectory(context);
        // 首选的缓存目录
        File preferredCacheDir = null;
        if (!TextUtils.isEmpty(cacheDir)) {
            preferredCacheDir = new File(cacheDir);
        } else {
            preferredCacheDir = reserveCacheDir;
        }
        DiskCache diskCache = null;
        try {
            diskCache = new LruDiskCache(preferredCacheDir, reserveCacheDir,
                    diskCacheFileNameGenerator, diskCacheSize, 0);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (diskCache == null) {
            diskCache = new UnlimitedDiskCache(preferredCacheDir, reserveCacheDir,
                    diskCacheFileNameGenerator);
        }
        return diskCache;
    }

    /**
     * 继续加载.常用于调用pause后恢复加载
     */
    public static void resume() {
        mImageLoader.resume();
    }

    /**
     * 暂停加载.常用于ListView等控件滚动时，来暂停图片加载
     */
    public static void pause() {
        mImageLoader.pause();
    }

    /**
     * 停止加载器.常用于退出程序时，清空加载队列
     */
    public static void stop() {
        mImageLoader.stop();
    }

    /**
     * 销毁加载器.清空加载队列，并且清除配置，恢复到初始状态，此时如需继续加载图片需要重新调用init方法
     */
    public static void destory() {
        mImageLoader.destroy();
    }

    public static DiskCache getDiskCache() {
        return mImageLoader.getDiskCache();
    }

    public static MemoryCache getMemoryCache() {
        return mImageLoader.getMemoryCache();
    }

    public static void setLogEnable(boolean logEnable) {
        L.writeLogs(logEnable);
    }

    /**
     * 获取已经使用的文件缓存的大小
     *
     * @return
     */
    @SuppressWarnings("deprecation")
    public static long getUsedDiskCacheSize() {
        long size = 0;
        DiskCache diskCache = mImageLoader.getDiskCache();
        File dir = diskCache.getDirectory();
        if (dir.exists() && dir.isDirectory()) {
            File[] files = dir.listFiles();
            for (File file : files) {
                if (file.isFile()) {
                    size += file.length();
                }
            }
        }
        return size;
    }

    /**
     * 获取已经使用的内存缓存的大小
     *
     * @return
     */
    @SuppressWarnings("deprecation")
    public static long getUsedMemoryCacheSize() {
        long size = 0;
        MemoryCache memoryCache = mImageLoader.getMemoryCache();
        for (String key : memoryCache.keys()) {
            Bitmap bitmap = memoryCache.get(key);
            if (bitmap != null && !bitmap.isRecycled()) {
                size += bitmap.getHeight() * bitmap.getRowBytes();
            }
        }
        return size;
    }

    /**
     * 清空文件缓存
     */
    public static void clearDiskCache() {
        mImageLoader.clearDiskCache();
    }

    /**
     * 清空内存缓存
     */
    public static void clearMemoryCache() {
        mImageLoader.clearMemoryCache();
    }

    /**
     * 获取最大图片大小.
     *
     * @return
     */
    private static ImageSize getMaxImageSize() {
        DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
        ImageSize maxImageSize = new ImageSize(displayMetrics.widthPixels,
                displayMetrics.heightPixels);
        return maxImageSize;
    }

    /**
     * 获取url对应的内存缓存key.
     *
     * @param uri
     * @param imageAware
     * @return
     */
    private static String getMemoryCacheKey(String uri, ImageAware imageAware) {
        if (imageAware == null) {
            imageAware = new NonViewAware(uri, getMaxImageSize(), ViewScaleType.CROP);
        }
        ImageSize targetSize = ImageSizeUtils
                .defineTargetSizeForView(imageAware, getMaxImageSize());
        return MemoryCacheUtils.generateKey(uri, targetSize);
    }

    /**
     * 获取uri对应的文件缓存key.
     *
     * @param uri
     * @return
     */
    private static String getDiskCacheKey(String uri) {
        return uri;
    }

    /**
     * 将bitmap放到MemoryCache中统一管理
     *
     * @param key
     * @param bitmap
     * @return
     */
    @SuppressWarnings("deprecation")
    public static boolean putMemoryCache(String key, Bitmap bitmap) {
        if (key == null) {
            return false;
        }
        MemoryCache memoryCache = mImageLoader.getMemoryCache();
        return memoryCache.put(getMemoryCacheKey(key, null), bitmap);
    }

    /**
     * 获取对应url和view大小的内存缓存图.
     *
     * @param url
     * @param view
     * @return
     */
    @SuppressWarnings("deprecation")
    public static Bitmap getMemoryCache(String url, View view) {
        if (url == null) {
            return null;
        }
        MemoryCache memoryCache = mImageLoader.getMemoryCache();
        String mkey = null;
        if (view == null) {
            mkey = getMemoryCacheKey(url, new NonViewAware(getMaxImageSize(), ViewScaleType.CROP));
        } else if (view instanceof ImageView) {
            mkey = getMemoryCacheKey(url, new ImageViewAware((ImageView) view));
        } else {
            mkey = getMemoryCacheKey(url, new SimpleViewAware(view));
        }
        return memoryCache.get(mkey);
    }

    /**
     * 获取对应url和view大小的文件缓存图.
     *
     * @param url
     * @param view
     * @return
     */
    @SuppressWarnings("deprecation")
    public static Bitmap getDiskCache(String url, View view) {
        if (url == null) {
            return null;
        }
        Bitmap bitmap = null;
        DiskCache diskCache = mImageLoader.getDiskCache();
        String dkey = getDiskCacheKey(url);
        File imageFile = diskCache.get(dkey);
        if (imageFile != null && imageFile.exists()) {
            // 获取ImageSize数据
            ImageSize targetSize = null;
            if (view == null) {
                targetSize = getMaxImageSize();
            } else if (view instanceof ImageView) {
                targetSize = ImageSizeUtils.defineTargetSizeForView(new ImageViewAware(
                        (ImageView) view), getMaxImageSize());
            } else {
                targetSize = ImageSizeUtils.defineTargetSizeForView(new SimpleViewAware(view),
                        getMaxImageSize());
            }
            // 同步加载文件缓存
            bitmap = mImageLoader.loadImageSync(Scheme.FILE.wrap(imageFile.getAbsolutePath()),
                    targetSize);
            if (bitmap != null && !bitmap.isRecycled()) {
                String mkey = null;
                if (view == null) {
                    mkey = getMemoryCacheKey(url, new NonViewAware(getMaxImageSize(),
                            ViewScaleType.CROP));
                } else if (view instanceof ImageView) {
                    mkey = getMemoryCacheKey(url, new ImageViewAware((ImageView) view));
                } else {
                    mkey = getMemoryCacheKey(url, new SimpleViewAware(view));
                }
                // 加载成功后转入内存缓存
                mImageLoader.getMemoryCache().put(mkey, bitmap);
            }
        }
        return bitmap;
    }

    /**
     * 获取对应url和view大小的内存缓存或者文件缓存图.
     *
     * @param url
     * @param view
     * @return
     */
    public static Bitmap getCache(String url, View view) {
        if (url == null) {
            return null;
        }
        Bitmap bitmap = null;
        bitmap = getMemoryCache(url, view);
        if (bitmap == null || bitmap.isRecycled()) {
            bitmap = getDiskCache(url, view);
        }
        return bitmap;
    }

    public static void display(String url, View view) {
        display(url, view, 0);
    }

    public static void display(String url, View view, int defaultRes) {
        display(url, view, defaultRes, DISPLAY_SIMPLE);
    }

    public static void display(String url, View view, int defaultRes, int displayType) {
        display(url, view, defaultRes, displayType, null);
    }

    public static void display(String url, View view, int defaultRes, int displayType,
                               ImageLoadingListener imageLoadingListener) {
        display(url, view, defaultRes, displayType, imageLoadingListener, null);
    }

    public static void display(String url, View view, int defaultRes, int displayType,
                               ImageLoadingListener imageLoadingListener,
                               ImageLoadingProgressListener imageLoadingProgressListener) {
        display(url, view, defaultRes, defaultRes, displayType, imageLoadingListener,
                imageLoadingProgressListener);
    }

    public static void display(String url, View view, int defaultRes, int failRes, int displayType,
                               ImageLoadingListener imageLoadingListener,
                               ImageLoadingProgressListener imageLoadingProgressListener) {
        display(url, view, defaultRes, failRes, defaultRes, displayType, imageLoadingListener,
                imageLoadingProgressListener);
    }

    public static void display(String url, View view, int defaultRes, int failRes, int emptyRes,
                               int displayType, ImageLoadingListener imageLoadingListener,
                               ImageLoadingProgressListener imageLoadingProgressListener) {
        create(url).setDefaultRes(defaultRes).setFailRes(failRes).setEmptyRes(emptyRes)
                .setDisplayType(displayType).setImageLoadingListener(imageLoadingListener)
                .setImageLoadingProgressListener(imageLoadingProgressListener).into(view);
    }

    public static void display(String url, View view, DisplayImageOptions displayImageOptions) {
        display(url, view, displayImageOptions, null, null);
    }

    public static void display(String url, View view, ImageLoadingListener imageLoadingListener) {
        display(url, view, null, imageLoadingListener, null);
    }

    public static void display(String url, View view, DisplayImageOptions displayImageOptions,
                               ImageLoadingListener imageLoadingListener) {
        display(url, view, displayImageOptions, imageLoadingListener, null);
    }

    public static void display(String url, View view, DisplayImageOptions displayImageOptions,
                               ImageLoadingListener imageLoadingListener,
                               ImageLoadingProgressListener imageLoadingProgressListener) {
        display(url, view, displayImageOptions, null, imageLoadingListener, imageLoadingProgressListener);
    }

    public static void display(String url, View view, DisplayImageOptions displayImageOptions, ImageSize imageSize,
                               ImageLoadingListener imageLoadingListener,
                               ImageLoadingProgressListener imageLoadingProgressListener) {
        try {
            if (view instanceof ImageView) {
                mImageLoader.displayImage(url, new ImageViewAware((ImageView) view),
                        displayImageOptions, imageSize, imageLoadingListener, imageLoadingProgressListener);
            } else if (view instanceof ImageSwitcher) {
                mImageLoader.displayImage(url, new ImageSwitcherAware(view), displayImageOptions, imageSize,
                        imageLoadingListener, imageLoadingProgressListener);
            } else {
                mImageLoader.displayImage(url, new SimpleViewAware(view), displayImageOptions, imageSize,
                        imageLoadingListener, imageLoadingProgressListener);
            }
        } catch (OutOfMemoryError | Exception error) {
            error.printStackTrace();
        }
    }

    public static void load(String url, ImageLoadingListener imageLoadingListener) {
        load(url, null, null, imageLoadingListener, null);
    }

    public static void load(String url, ImageSize targetImageSize,
                            ImageLoadingListener imageLoadingListener) {
        load(url, targetImageSize, null, imageLoadingListener, null);
    }

    public static void load(String url, DisplayImageOptions displayImageOptions,
                            ImageLoadingListener imageLoadingListener) {
        load(url, null, displayImageOptions, imageLoadingListener, null);
    }

    public static void load(String url, ImageSize targetImageSize,
                            DisplayImageOptions displayImageOptions, ImageLoadingListener imageLoadingListener) {
        load(url, targetImageSize, displayImageOptions, imageLoadingListener, null);
    }

    public static void load(String url, ImageSize targetImageSize,
                            DisplayImageOptions displayImageOptions, ImageLoadingListener imageLoadingListener,
                            ImageLoadingProgressListener imageLoadingProgressListener) {
        try {
            mImageLoader.loadImage(url, targetImageSize, displayImageOptions, imageLoadingListener,
                    imageLoadingProgressListener);
        } catch (OutOfMemoryError | Exception error) {
            error.printStackTrace();
        }
    }

    public static Bitmap loadSync(String url, ImageSize targetImageSize,
                                  DisplayImageOptions displayImageOptions) {
        try {
            return mImageLoader.loadImageSync(url, targetImageSize, displayImageOptions);
        } catch (OutOfMemoryError | Exception error) {
            error.printStackTrace();
        }
        return null;
    }

    public static Builder create(String url) {
        return new Builder(url);
    }

    public static class Builder {

        private String mUrl;
        private int mDefaultRes;
        private int mFailRes;
        private int mEmptyRes;
        private Drawable mDefaultDrawable;
        private Drawable mFailDrawable;
        private Drawable mEmptyDrawable;
        private int mDisplayType = DISPLAY_SIMPLE;
        private int mRoundRadius = 5;
        private int mBlurDepth = 10;
        private int mFadeOutTime = 500;
        private int mFadeInTime = 500;
        private boolean mMemoryCacheEnable = true;
        private boolean mDiskCacheEnable = true;
        private boolean mFadeInLoadFromDisc = true;
        private boolean mFadeInLoadFromMemory = false;
        private boolean mFadeInLoadFromNetwork = true;
        private boolean mFadeOutLoadFromDisc = true;
        private boolean mFadeOutLoadFromMemory = true;
        private boolean mFadeOutLoadFromNetwork = true;
        private ImageLoadingListener mImageLoadingListener;
        private ImageLoadingProgressListener mImageLoadingProgressListener;
        private ImageSize mImageSize;
        private ImageScaleType mImageScaleType = ImageScaleType.EXACTLY;
        private boolean mConsiderExifParams = false;
        private Options mDecodingOptions = new Options();
        private float mFadeInOriginAlpha = 0.0f;
        private float mFadeInTargetAlpha = 1.0f;
        private float mFadeOutOriginAlpha = 1.0f;
        private float mFadeOutTargetAlpha = 0.0f;

        Builder(String url) {
            this.mUrl = url;
            this.mDecodingOptions.inPreferredConfig = Config.RGB_565;
            this.mDecodingOptions.inSampleSize = 1;
        }

        public Builder setCacheInMemory(boolean enable) {
            mMemoryCacheEnable = enable;
            return this;
        }

        public Builder setCacheInDisk(boolean enable) {
            mDiskCacheEnable = enable;
            return this;
        }

        public Builder setConsiderExifParams(boolean considerExifParams) {
            mConsiderExifParams = considerExifParams;
            return this;
        }

        public Builder setFadeInLoadFromDisc(boolean fadeLoadFromDisc) {
            mFadeInLoadFromDisc = fadeLoadFromDisc;
            return this;
        }

        public Builder setFadeInLoadFromMemory(boolean fadeLoadFromMemory) {
            mFadeInLoadFromMemory = fadeLoadFromMemory;
            return this;
        }

        public Builder setFadeInLoadFromNetwork(boolean fadeLoadFromNetwork) {
            mFadeInLoadFromNetwork = fadeLoadFromNetwork;
            return this;
        }

        public Builder setFadeOutLoadFromDisc(boolean fadeLoadFromDisc) {
            mFadeOutLoadFromDisc = fadeLoadFromDisc;
            return this;
        }

        public Builder setFadeOutLoadFromMemory(boolean fadeLoadFromMemory) {
            mFadeOutLoadFromMemory = fadeLoadFromMemory;
            return this;
        }

        public Builder setFadeOutLoadFromNetwork(boolean fadeLoadFromNetwork) {
            mFadeOutLoadFromNetwork = fadeLoadFromNetwork;
            return this;
        }

        public Builder setInSampleSize(int inSampleSize) {
            this.mDecodingOptions.inSampleSize = inSampleSize;
            return this;
        }

        public Builder setBitmapConfig(Config config) {
            this.mDecodingOptions.inPreferredConfig = config;
            return this;
        }

        public Builder setImageScaleType(ImageScaleType scaleType) {
            this.mImageScaleType = scaleType;
            return this;
        }

        public Builder setDefaultDrawable(Drawable drawable) {
            this.mDefaultDrawable = drawable;
            return this;
        }

        public Builder setFailDrawable(Drawable drawable) {
            this.mFailDrawable = drawable;
            return this;
        }

        public Builder setEmptyDrawable(Drawable drawable) {
            this.mEmptyDrawable = drawable;
            return this;
        }

        /**
         * 设置默认资源
         *
         * @param res
         * @return
         */
        public Builder setDefaultRes(int res) {
            this.mDefaultRes = res;
            return this;
        }

        /**
         * 设置错误资源
         *
         * @param res
         * @return
         */
        public Builder setFailRes(int res) {
            this.mFailRes = res;
            return this;
        }

        /**
         * 设置空资源
         *
         * @param res
         * @return
         */
        public Builder setEmptyRes(int res) {
            this.mEmptyRes = res;
            return this;
        }

        /**
         * 设置显示类型
         *
         * @param displayType
         * @return
         */
        public Builder setDisplayType(int displayType) {
            this.mDisplayType = displayType;
            return this;
        }

        /**
         * 设置圆角
         *
         * @param roundRadius
         * @return
         */
        public Builder setRoundRadius(int roundRadius) {
            this.mRoundRadius = roundRadius;
            return this;
        }

        /**
         * 设置高斯模糊深度
         *
         * @param blurDepth
         * @return
         */
        public Builder setBlurDepth(int blurDepth) {
            this.mBlurDepth = blurDepth;
            return this;
        }

        /**
         * 设置渐入时间
         *
         * @param fadeInTime
         * @return
         */
        public Builder setFadeInTime(int fadeInTime) {
            this.mFadeInTime = fadeInTime;
            return this;
        }

        /**
         * 设置渐出时间
         *
         * @param mFadeOutTime
         * @return
         */
        public Builder setFadeOutTime(int mFadeOutTime) {
            this.mFadeOutTime = mFadeOutTime;
            return this;
        }

        public Builder setImageLoadingListener(ImageLoadingListener listener) {
            this.mImageLoadingListener = listener;
            return this;
        }

        public Builder setImageLoadingProgressListener(ImageLoadingProgressListener listener) {
            this.mImageLoadingProgressListener = listener;
            return this;
        }

        public Builder setImageSize(ImageSize imageSize) {
            this.mImageSize = imageSize;
            return this;
        }

        public Builder setFadeInOriginAlpha(float mFadeInOriginAlpha) {
            this.mFadeInOriginAlpha = mFadeInOriginAlpha;
            return this;
        }

        public Builder setFadeInTargetAlpha(float mFadeInTargetAlpha) {
            this.mFadeInTargetAlpha = mFadeInTargetAlpha;
            return this;
        }

        public Builder setFadeOutOriginAlpha(float mFadeOutOriginAlpha) {
            this.mFadeOutOriginAlpha = mFadeOutOriginAlpha;
            return this;
        }

        public Builder setFadeOutTargetAlpha(float mFadeOutTargetAlpha) {
            this.mFadeOutTargetAlpha = mFadeOutTargetAlpha;
            return this;
        }

        private DisplayImageOptions build() {
            if (this.mFailRes <= 0) {
                this.mFailRes = this.mDefaultRes;
            }
            if (this.mEmptyRes <= 0) {
                this.mEmptyRes = this.mDefaultRes;
            }
            if (this.mFailDrawable == null) {
                this.mFailDrawable = this.mDefaultDrawable;
            }
            if (this.mEmptyDrawable == null) {
                this.mEmptyDrawable = this.mDefaultDrawable;
            }

            DisplayImageOptions.Builder builder = new DisplayImageOptions.Builder()
                    .showImageOnFail(this.mFailDrawable).showImageForEmptyUri(this.mEmptyDrawable)
                    .showImageOnLoading(this.mDefaultDrawable).showImageOnFail(this.mFailRes)
                    .showImageForEmptyUri(this.mEmptyRes).showImageOnLoading(this.mDefaultRes)
                    .imageScaleType(mImageScaleType).cacheInMemory(mMemoryCacheEnable)
                    // 除了Http和Https打头的请求，都不进行文件缓存，以防出现比如Drawable文件更新，而因为文件缓存导致显示错误的问题。
                    .cacheOnDisk(mDiskCacheEnable && (Scheme.ofUri(this.mUrl).equals(Scheme.HTTP) || Scheme.ofUri(this.mUrl).equals(Scheme.HTTPS)))
                    .decodingOptions(mDecodingOptions).considerExifParams(mConsiderExifParams);
            DisplayImageOptions displayImageOptions = null;
            switch (mDisplayType) {
                case DISPLAY_FADE_OUT:
                    displayImageOptions = builder.displayer(
                            new FadeOutBitmapDisplayer(mFadeOutTime, mFadeOutLoadFromNetwork,
                                    mFadeOutLoadFromDisc, mFadeOutLoadFromMemory, mFadeOutOriginAlpha,
                                    mFadeOutTargetAlpha)).build();
                    break;
                case DISPLAY_ROUND:
                    displayImageOptions = builder.displayer(new RoundedBitmapDisplayer(mRoundRadius))
                            .build();
                    break;
                case DISPLAY_ROUND_VIGNETTE:
                    displayImageOptions = builder.displayer(
                            new RoundedVignetteBitmapDisplayer(mRoundRadius)).build();
                    break;
                case DISPLAY_CIRCLE:
                    displayImageOptions = builder.displayer(new CircleBitmapDisplayer()).build();
                    break;
                case DISPLAY_BLUR:
                    displayImageOptions = builder.displayer(new BlurBitmapDisplayer(mBlurDepth))
                            .build();
                    break;
                case DISPLAY_FADE_IN:
                case DISPLAY_SIMPLE | DISPLAY_FADE_IN:
                    displayImageOptions = builder.displayer(
                            new FadeInBitmapDisplayer(mContext, mFadeInTime, mFadeInLoadFromNetwork,
                                    mFadeInLoadFromDisc, mFadeInLoadFromMemory)).build();
                    break;
                case DISPLAY_ROUND | DISPLAY_FADE_IN:
                    displayImageOptions = builder.displayer(
                            new RoundedFadeInBitmapDisplayer(mRoundRadius, 0, mFadeInTime,
                                    mFadeInLoadFromNetwork, mFadeInLoadFromDisc, mFadeInLoadFromMemory,
                                    mFadeInOriginAlpha, mFadeInTargetAlpha)).build();
                    break;
                case DISPLAY_ROUND | DISPLAY_BLUR:
                    displayImageOptions = builder.displayer(
                            new RoundedBlurBitmapDisplayer(mRoundRadius, mBlurDepth)).build();
                    break;
                case DISPLAY_ROUND_VIGNETTE | DISPLAY_FADE_IN:
                    displayImageOptions = builder
                            .displayer(
                                    new RoundedVignetteFadeInBitmapDisplayer(mRoundRadius, mFadeInTime,
                                            mFadeInLoadFromNetwork, mFadeInLoadFromDisc,
                                            mFadeInLoadFromMemory)).build();
                    break;
                case DISPLAY_ROUND_VIGNETTE | DISPLAY_BLUR:
                    displayImageOptions = builder.displayer(
                            new RoundedVignetteBlurBitmapDisplayer(mRoundRadius, mBlurDepth)).build();
                    break;
                case DISPLAY_CIRCLE | DISPLAY_FADE_IN:
                    displayImageOptions = builder.displayer(
                            new CircleFadeInBitmapDisplayer(mFadeInTime, mFadeInLoadFromNetwork,
                                    mFadeInLoadFromDisc, mFadeInLoadFromMemory)).build();
                    break;
                case DISPLAY_CIRCLE | DISPLAY_BLUR:
                    displayImageOptions = builder.displayer(new CircleBlurBitmapDisplayer(mBlurDepth))
                            .build();
                    break;
                case DISPLAY_BLUR | DISPLAY_FADE_IN:
                    displayImageOptions = builder
                            .displayer(
                                    new BlurFadeInBitmapDisplayer(mBlurDepth, mFadeInTime,
                                            mFadeInLoadFromNetwork, mFadeInLoadFromDisc,
                                            mFadeInLoadFromMemory)).build();
                    break;
                case DISPLAY_CIRCLE_RING:
                    displayImageOptions = builder.displayer(new CircleRingBitmapDisplayer()).build();
                    break;
                case DISPLAY_SIMPLE:
                default:
                    displayImageOptions = builder.displayer(new SimpleBitmapDisplayer()).build();
                    break;
            }

            return displayImageOptions;
        }

        public void load() {
            EZImageLoader.load(this.mUrl, this.mImageSize, build(), this.mImageLoadingListener,
                    this.mImageLoadingProgressListener);
        }

        public void into(View view) {
            EZImageLoader.display(this.mUrl, view, build(), this.mImageSize, this.mImageLoadingListener,
                    this.mImageLoadingProgressListener);
        }
    }

    /**
     * 默认的图片加载监听器，所有方法均为空需要子类覆盖实现
     */
    public abstract static class DefaultLoadingListener implements ImageLoadingListener {

        @Override
        public void onLoadingStarted(String s, View view) {
        }

        @Override
        public void onLoadingFailed(String s, View view, FailReason failReason) {
        }

        @Override
        public void onLoadingComplete(String s, View view, Bitmap bitmap) {
        }

        @Override
        public void onLoadingCancelled(String s, View view) {
        }
    }
}
